﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;

using System.Xml;

namespace SPMergeWebConfig
{
    class Program
    {
        static void Main(string[] args)
        {

            if ((args.Length != 0) && (args[0].Contains("?")))
            {
                // show syntax
                Usage();
                return;
            }

            if (args.Length != 4)
            {
                // show syntax
                Usage();
                return;
            }

            string filename;
            string directoryPath;

            if ((args[0].Trim() == "-file") && (args[2].Trim() == "-mergefile"))
            {
                filename = args[1];
                directoryPath = args[3];
            }
            else
            {
                if ((args[0].Trim() == "-mergefile") && (args[2].Trim() == "-file"))
                {
                    filename = args[3];
                    directoryPath = args[1];
                }
                else
                {
                    Usage();
                    return;
                }
            }


            var xdWebConfig = new XmlDocument();
            xdWebConfig.Load(filename + @"\web.config");

            MergeWebConfig(xdWebConfig, directoryPath, "webconfig.*.xml");
            xdWebConfig.Save(filename);

        }
        private static void Usage()
        {
            Console.WriteLine(@"=============================================================================");
            Console.WriteLine("");
            Console.WriteLine(@"Usage : ");
            Console.WriteLine("");
            Console.WriteLine(@"SPMergeWebConfig.exe -file 'C:\Inetpub\wwwroot\wss\VirtualDirectories\80\' -mergefile C:\Inetpub\wwwroot\wss\VirtualDirectories\80\");
            Console.WriteLine("");
            Console.WriteLine(@"Note : 1. Merge file name(s) should be webconfig.*.xml ");
            Console.WriteLine(@"       i.e.  webconfig.changes.xml, webconfig.merge.xml  ");
            Console.WriteLine(@"     : 2. You can have more than one file to be merged ");
            Console.WriteLine("");
            Console.WriteLine(@"Help : ");
            Console.WriteLine("");
            Console.WriteLine(@"SPMergeWebConfig.exe ? ");
            Console.WriteLine("");
            Console.WriteLine(@"==============================================================================");
            Console.ReadLine();

        }
        internal static void MergeWebConfig(XmlDocument xdWebConfig, string directoryPath, string fileMask)
        {
            FileInfo[] infoArray2;
            int num;
            FileInfo[] files = new DirectoryInfo(directoryPath).GetFiles(fileMask);
            if (files.Length != 0)
            {
                infoArray2 = files;
                num = 0;
            }
            else
            {
                return;
            }
            while (num < infoArray2.Length)
            {
                FileInfo info2 = infoArray2[num];
                var xdAction = new XmlDocument();
                xdAction.Load(info2.FullName);
                ApplyActionToXmlDocument(xdAction, xdWebConfig, info2.FullName);
                num++;
            }
        }

        private static void ApplyActionToXmlDocument(XmlDocument xdAction, XmlDocument xd, string sourceFileName)
        {
            XmlNode node5;
            XmlNodeList childNodes = xdAction.DocumentElement.ChildNodes;
            var nsmgr = new XmlNamespaceManager(xd.NameTable);
            nsmgr.AddNamespace("ns", "urn:schemas-microsoft-com:asm.v1");
            if (xd.SelectSingleNode("configuration/configSections/sectionGroup[@name='SharePoint']/section[@name='MergedActions']") == null)
            {
                XmlNode node2 = xd.SelectSingleNode("configuration/configSections/sectionGroup[@name='SharePoint']");
                if (node2 == null)
                {
                    throw new InvalidDataException("WebConfigInvalidElement: Configuration/configSections/sectionGroup[@name='SharePoint'] missing");
                }
                XmlNode node = node2.AppendChild(xd.CreateElement("section"));
                node.Attributes.Append(xd.CreateAttribute("name")).Value = "MergedActions";
                node.Attributes.Append(xd.CreateAttribute("type")).Value = "System.Configuration.SingleTagSectionHandler, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089";
            }
            XmlNode documentElement = xd.DocumentElement;
            XmlNode node4 = documentElement["SharePoint"];
            if (node4 == null)
            {
                node4 = documentElement.AppendChild(xd.CreateElement("SharePoint"));
            }
            node5 = node4["MergedActions"];
            if (node5 == null)
            {
                node5 = node4.AppendChild(xd.CreateElement("MergedActions"));
            }
            Dictionary<Guid, bool> dictionary = ExtractMergedActionIds(xd);
            {
                IEnumerator enumerator = childNodes.GetEnumerator();

                XmlNode node6;
                string str2;
                XmlNode node7;
                string str3;
                XmlNode node9;
                XmlNode node11;
                XmlNode node14;
                IEnumerator enumerator2;
                IEnumerator enumerator3;
            Label_0098:
                if (enumerator.MoveNext())
                {
                    goto Label_00C4;
                }
                return;
            Label_00A9:
                if (!(node6.Name == "remove"))
                {
                    goto Label_02EB;
                }
                goto Label_015B;
            Label_00C4:
                node6 = (XmlNode)enumerator.Current;
                Guid empty = Guid.Empty;
                XmlAttribute attribute = node6.Attributes["id"];
                if (attribute == null)
                {
                    goto Label_03F6;
                }
                goto Label_0259;
            Label_00F8:
                if (node6.Attributes["path"] == null)
                {
                    goto Label_0149;
                }
                goto Label_0212;
            Label_0113:
                if (!(node6.Name == "add"))
                {
                    goto Label_0149;
                }
                goto Label_00F8;
            Label_012B:
                if (node7.NodeType != XmlNodeType.Element)
                {
                    goto Label_03E3;
                }
                goto Label_0191;
            Label_013A:
                if (node11.NodeType != XmlNodeType.Element)
                {
                    goto Label_03E3;
                }
                goto Label_01B3;
            Label_0149:
                if (node6.NodeType != XmlNodeType.Element)
                {
                    goto Label_02EB;
                }
                goto Label_00A9;
            Label_015B:
                if (node6.Attributes["path"] == null)
                {
                    goto Label_02EB;
                }
                goto Label_03B4;
            Label_0176:
                if (!(node6.Name == "update"))
                {
                    goto Label_03E3;
                }
                goto Label_04A8;
            Label_0191:
                enumerator2 = node6.ChildNodes.GetEnumerator();
                goto Label_01C6;
            Label_01A1:
                if (node6.NodeType != XmlNodeType.Element)
                {
                    goto Label_0149;
                }
                goto Label_0113;
            Label_01B3:
                enumerator3 = node6.ChildNodes.GetEnumerator();
                goto Label_030F;
            Label_01C6:
                try
                {
                    while (enumerator2.MoveNext())
                    {
                        var current = (XmlNode)enumerator2.Current;
                        node7.AppendChild(xd.ImportNode(current, true));
                    }
                    goto Label_03E3;
                }
                finally
                {
                    var disposable = enumerator2 as IDisposable;
                    if (disposable != null)
                    {
                        disposable.Dispose();
                    }
                }
            Label_0212:
                str2 = node6.Attributes["path"].Value;
                node7 = xd.SelectSingleNode(str2, nsmgr);
                if (node7 == null)
                {
                    goto Label_03E3;
                }
                goto Label_012B;
            Label_0241:
                node9.ParentNode.RemoveChild(node9);
                goto Label_03E3;
            Label_0259:
                try
                {
                    string g = attribute.Value;
                    empty = new Guid(g);
                    if (!dictionary.ContainsKey(empty))
                    {
                        goto Label_01A1;
                    }
                    //ULS.SendTraceTag(ULSTagID.tag_886w, ULSCat.msoulscat_WSS_Topology, ULSTraceLevel.Medium, "Action %s from %s has already been applied to the web.config and will be bypassed.", new object[] { g, sourceFileName });
                    goto Label_0098;
                }
                catch (Exception exception)
                {
                    //ULS.SendTraceTag(ULSTagID.tag_886x, ULSCat.msoulscat_WSS_Topology, ULSTraceLevel.Medium, "The following error occured while processing %s for existing web.config merge actions.  The action may be reapplied to the web.config, causing duplicate data: %s", new object[] { sourceFileName, exception.Message });
                    empty = Guid.Empty;
                    goto Label_01A1;
                }
            Label_02EB:
                if (node6.NodeType != XmlNodeType.Element)
                {
                    goto Label_03E3;
                }
                goto Label_0176;
            Label_02FD:
                if (node9.NodeType != XmlNodeType.Element)
                {
                    goto Label_03E3;
                }
                goto Label_0497;
            Label_030F:
                try
                {
                    XmlNode node13;
                    IEnumerator enumerator4;
                Label_033F:
                    while (enumerator3.MoveNext())
                    {
                        var node12 = (XmlNode)enumerator3.Current;
                        node13 = node11.SelectSingleNode(node12.Name);
                        enumerator4 = node12.Attributes.GetEnumerator();
                        goto Label_034A;
                    }
                    goto Label_03E3;
                Label_034A:
                    try
                    {
                        while (enumerator4.MoveNext())
                        {
                            var attribute2 = (XmlAttribute)enumerator4.Current;
                            SetNamedStringItem(xd, node13, attribute2.Name, attribute2.Value);
                        }
                        goto Label_033F;
                    }
                    finally
                    {
                        IDisposable disposable2 = enumerator4 as IDisposable;
                        if (disposable2 != null)
                        {
                            disposable2.Dispose();
                        }
                    }
                    goto Label_03E3;
                }
                finally
                {
                    IDisposable disposable3 = enumerator3 as IDisposable;
                    if (disposable3 != null)
                    {
                        disposable3.Dispose();
                    }
                }
            Label_03B4:
                str3 = node6.Attributes["path"].Value;
                node9 = xd.SelectSingleNode(str3, nsmgr);
                if (node9 != null)
                {
                    goto Label_02FD;
                }
            Label_03E3:
                if (!(empty != Guid.Empty))
                {
                    goto Label_0098;
                }
                goto Label_0420;
            Label_03F6: ;
                // ULS.SendTraceTag(ULSTagID.tag_886y, ULSCat.msoulscat_WSS_Topology, ULSTraceLevel.High, "An action in %s does not contain an id attribute with a unique guid value.  This action may be performed repeatedly, causing duplicate entries in the web.config.", new object[] { sourceFileName });
                goto Label_01A1;
            Label_0420:
                node14 = node5.AppendChild(xd.CreateElement("Action"));
                XmlAttribute attribute3 = xd.CreateAttribute("id");
                attribute3.Value = empty.ToString();
                node14.Attributes.Append(attribute3);
                XmlAttribute attribute4 = xd.CreateAttribute("sourceFile");
                attribute4.Value = sourceFileName;
                node14.Attributes.Append(attribute4);
                dictionary[empty] = true;
                goto Label_0098;
            Label_0497:
                if (node9.ParentNode == null)
                {
                    goto Label_03E3;
                }
                goto Label_0241;
            Label_04A8:
                if (node6.Attributes["path"] == null)
                {
                    goto Label_03E3;
                }
                string xpath = node6.Attributes["path"].Value;
                node11 = xd.SelectSingleNode(xpath);
                if (node11 == null)
                {
                    goto Label_03E3;
                }
                goto Label_013A;
            }
        }
        internal static string SetNamedStringItem(XmlDocument xdDoc, XmlNode node, string strName, string strValue)
        {
            XmlNode namedItem = node.Attributes.GetNamedItem(strName);
            if (namedItem == null)
            {
                XmlAttribute attribute = xdDoc.CreateAttribute(strName);
                attribute.Value = strValue;
                node.Attributes.SetNamedItem(attribute);
                return strValue;
            }
            namedItem.Value = strValue;
            return strValue;
        }
        private static Dictionary<Guid, bool> ExtractMergedActionIds(XmlDocument doc)
        {
            Dictionary<Guid, bool> dictionary = new Dictionary<Guid, bool>();
            XmlNode node = doc.DocumentElement["SharePoint"];
            if (node != null)
            {
                XmlNode node2 = node["MergedActions"];
                if (node2 != null)
                {

                    {
                        IEnumerator enumerator = node2.ChildNodes.GetEnumerator();

                        XmlNode node3;
                    Label_0024:
                        if (enumerator.MoveNext())
                        {
                            goto Label_0095;
                        }
                        return dictionary;
                    Label_002F:
                        try
                        {
                            XmlAttribute attribute = node3.Attributes["id"];
                            if (attribute != null)
                            {
                                string g = attribute.Value;
                                Guid guid = new Guid(g);
                                dictionary[guid] = true;
                            }
                        }
                        catch (Exception exception)
                        {
                            //ULS.SendTraceTag(ULSTagID.tag_886z, ULSCat.msoulscat_WSS_Topology, ULSTraceLevel.High, "An unexpected exception occured while attempting to parse a web.config file for merged actions.  Duplicate actions may be performed on the web.config file.  The exception contained the following additional information: %s.", new object[] { exception.Message });
                        }
                        goto Label_0024;
                    Label_0095:
                        node3 = (XmlNode)enumerator.Current;
                        goto Label_002F;
                    }
                }
                return dictionary;
            }
            return dictionary;
        }
    }
}
